package com.google.code.jtasks.bugzilla.proxy.user;

import java.util.HashMap;
import java.util.Map;

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;

import com.google.code.jtasks.bugzilla.proxy.ProcessingUtils;

/**
 * This class provides a proxy for the <code>User.login</code> XML-RPC method.
 */
public final class UserLoginProxy
{
	private final XmlRpcClient rpcClient;

	/**
	 * Constructs a new {@link UserLoginProxy} instance.
	 * 
	 * @param rpcClient
	 *            the {@link XmlRpcClient} that should be used
	 */
	public UserLoginProxy(XmlRpcClient rpcClient)
	{
		this.rpcClient = rpcClient;
	}

	/**
	 * This method is a proxy for the <code>Bug.history</code> XML-RPC method.
	 * 
	 * @param params
	 *            the {@link LoginParams} that specifies which comments should be returned
	 * @return a {@link LoginResult} object containing the results of the search
	 */
	public LoginResult login(LoginParams params)
	{
		Object rpcResultStruct;
		try
		{
			rpcResultStruct = rpcClient.execute("User.login", new Object[] { params.convertToRpcStruct() });
		}
		catch (XmlRpcException e)
		{
			// TODO throw a better exception
			throw new RuntimeException(e);
		}

		return new LoginResult(rpcResultStruct);
	}

	/**
	 * Represents the parameters that can be passed to the <code>User.login</code> XML-RPC method.
	 */
	public static final class LoginParams
	{
		private String login;
		private String password;
		private Boolean remember;

		/**
		 * Constructs a new {@link LoginParams} instance.
		 */
		public LoginParams()
		{
			this.login = null;
			this.password = null;
			this.remember = null;
		}

		/**
		 * Sets the user's login name.
		 * 
		 * @param login
		 *            The user's login name.
		 */
		public void setLogin(String login)
		{
			this.login = login;
		}

		/**
		 * Sets the user's password.
		 * 
		 * @param password
		 *            The user's password.
		 */
		public void setPassword(String password)
		{
			this.password = password;
		}

		/**
		 * Sets whether the cookies returned by the call to login should expire with the session or not. In
		 * order for this option to have effect the Bugzilla server must be configured to allow the user to
		 * set this option - the Bugzilla parameter rememberlogin must be set to "defaulton" or "defaultoff".
		 * Addionally, the client application must implement management of cookies across sessions.
		 * 
		 * @param remember
		 *            Whether the cookies returned by the call to login should expire with the session or not.
		 */
		public void setRemember(Boolean remember)
		{
			this.remember = remember;
		}

		/**
		 * Converts this {@link LoginParams} instance to a "raw" struct that can be passed to an
		 * {@link XmlRpcClient}.
		 * 
		 * @return a "raw" struct that can be passed to an {@link XmlRpcClient}
		 */
		Map<String, Object> convertToRpcStruct()
		{
			Map<String, Object> rpcStruct = new HashMap<String, Object>();

			rpcStruct.put("login", login);
			rpcStruct.put("password", password);
			rpcStruct.put("remember", remember);

			return rpcStruct;
		}
	}

	/**
	 * Represents the result returned by the <code>User.login</code> XML-RPC method.
	 */
	public static final class LoginResult
	{
		private final Integer id;

		/**
		 * Constructs a new {@link LoginResult} instance from the specified
		 * {@link XmlRpcClient#execute(String, Object[])} result object.
		 * 
		 * @param rpcResultStruct
		 *            the {@link XmlRpcClient#execute(String, Object[])} result object to build the
		 *            {@link LoginResult} from
		 */
		public LoginResult(Object rpcResultStruct)
		{
			Map<?, ?> rootMap = ProcessingUtils.castToMap(rpcResultStruct);
			this.id = ProcessingUtils.extractIntegerField(rootMap, "id", false);
		}

		/**
		 * Returns the numeric id of the user that was logged in.
		 * 
		 * @return the numeric id of the user that was logged in
		 */
		public Integer getId()
		{
			return id;
		}
	}
}
